#include "AVFormatX.h"
#include "AVCodecX.h"
namespace FFMPEGCPP
{
bool m_bavformat_inited = false;

bool InitFormat()
{
	if(m_bavformat_inited)return true;

	av_register_all();
	avformat_network_init();

	m_bavformat_inited = true;

	return true;
}

void UnInitFormat()
{
	if( false == m_bavformat_inited )return;
	avformat_network_deinit();

	m_bavformat_inited = false;

}

void packetque_init( PacketQueue* p )
{
	p->first = 0;
	p->last = 0;
	p->nb_packets = 0;
	p->size = 0;
}

bool packetque_pushback( PacketQueue* p,AVPacket* packet )
{
	AVPacketList* pPacketList;
	if(av_dup_packet(packet) < 0) 
	{
		return false;
	}

	pPacketList = (AVPacketList *)av_malloc(sizeof(AVPacketList));
	if( 0 == pPacketList )return false;

	pPacketList->pkt = *packet;
	pPacketList->next = NULL;

	if( 0 == p->last )
	{
		p->first = pPacketList;
	}else
	{
		p->last->next = pPacketList;
	}

	p->last = pPacketList;

	p->nb_packets ++;
	p->size += packet->size;

	return true;
}

bool packetque_popfront( PacketQueue* p,AVPacket* packet )
{
	AVPacketList* pPacketList;

	pPacketList = p->first;
	if( 0 == pPacketList )return false;

	p->first = p->first->next;

	if( 0 == p->first )p->last = 0;

	*packet = pPacketList->pkt;
	av_free(pPacketList);

	p->nb_packets --;
	p->size -= packet->size;

	return true;
}
CAVInputFile::CAVInputFile()
{
	m_pAVInputFormat = 0;
	m_pFormatCtx = 0;
	m_pDecodeList = 0;
	m_Duration = 0;
}

CAVInputFile::~CAVInputFile()
{
	if(m_pFormatCtx)Close();

}

bool CAVInputFile::Open( const char* filename,const char* formatname /*= 0 */ )
{
	int nRet = 0;

	if(formatname)
	{
		m_pAVInputFormat = av_find_input_format( formatname );

		m_pFormatCtx = avformat_alloc_context();

		m_pFormatCtx->video_codec_id = AV_CODEC_ID_NONE;
		m_pFormatCtx->audio_codec_id = AV_CODEC_ID_NONE;
		m_pFormatCtx->subtitle_codec_id = AV_CODEC_ID_NONE;

	}

	nRet = avformat_open_input( &m_pFormatCtx,filename,m_pAVInputFormat,0 );
	if( nRet )return false;

	//av_dump_format(  );

	if( 0!= avformat_find_stream_info( m_pFormatCtx,0) )return false;

	m_Duration = m_pFormatCtx->duration;
	//AV_TIME_BASE

	return true;

}

void CAVInputFile::Close()
{
	if(m_pFormatCtx)avformat_close_input( &m_pFormatCtx );	
	if(m_pFormatCtx)avformat_free_context( m_pFormatCtx );	
	m_pAVInputFormat = 0;
	m_pFormatCtx = 0;

	if( m_pDecodeList )
	{
		delete m_pDecodeList;
	}
	m_pDecodeList = 0;
}

bool CAVInputFile::ReadPacket( AVPacket* pPacket )
{
	//av_seek_frame( AVSEEK_FLAG_BACKWARD
	if( av_read_frame( m_pFormatCtx,pPacket ) < 0 )return false;

	return true;
}

void CAVInputFile::FreePacket( AVPacket* pPacket )
{
	av_free_packet( pPacket );
	memset( pPacket,0,sizeof(AVPacket) );
}

AVFormatContext* CAVInputFile::GetContext()
{
	return m_pFormatCtx;
}

unsigned int CAVInputFile::GetStreamCount()
{
	if( 0 == m_pFormatCtx )return 0;
	return m_pFormatCtx->nb_streams;
}

enum AVMediaType CAVInputFile::GetStreamMediaType( unsigned int nStreamIndex )
{
	if( nStreamIndex <0 || nStreamIndex >= GetStreamCount() )return AVMEDIA_TYPE_UNKNOWN;

	return m_pFormatCtx->streams[nStreamIndex]->codec->codec_type;
}

bool CAVInputFile::SetDecodeForStream( unsigned int nStreamIndex,CAVDecodeBase* decoder )
{
	if( nStreamIndex < 0 || nStreamIndex > GetStreamCount() )return false;

	if( 0 == m_pDecodeList )
	{
		m_pDecodeList = new CAVDecodeBase*[GetStreamCount()];
		memset( m_pDecodeList,0,sizeof(CAVDecodeBase*)*GetStreamCount());
	}

	m_pDecodeList[nStreamIndex] = decoder;

	return true;
}

bool CAVInputFile::ProcessPacket()
{
	AVPacket		packet = {0};
	CAVDecodeBase*	pDecoder;
	bool			bRet = false;;

	if( false == ReadPacket( &packet ) )return false;

	do 
	{
		if( 0 == m_pDecodeList )break;

		bRet = true;
		if( packet.stream_index < 0 || packet.stream_index > GetStreamCount() )break;

		pDecoder = m_pDecodeList[packet.stream_index];
		if( 0 == pDecoder )break;

		pDecoder->WritePacket( &packet );
		return true;
	} while (0);

	FreePacket( &packet );

	return bRet;
}

CAVDecodeBase* CAVInputFile::GetDecode( unsigned int nStreamIndex )
{
	if( nStreamIndex < 0 || nStreamIndex > GetStreamCount() )return 0;

	return m_pDecodeList[nStreamIndex];
}

int64_t CAVInputFile::GetTotalTime()
{
	return m_Duration;
}


}
